package com.ccp.dev.core.util;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;
import static com.ccp.dev.core.util.ReflectionUtil.getFieldGetter;
import static com.ccp.dev.core.util.ReflectionUtil.getFieldValue;

/**
 * 实体拷贝.
 * User: 张为
 * Date: 2015/1/15
 * Time: 14:44
 */
public abstract class BeanCopyUtil {

    private static final String SET_METHOD_PREFIX = "set";

    /**
     * 实体拷贝
     * <ul>
     * <li>支持基本类型和包装类型（比如int和Integer、long和Long）之间的拷贝，只要属性名一致即可</li>
     * <li>实体属性可以定义WomaiField，如果canCopy为false，则该属性不拷贝</li>
     * <li>源目标的父类属性也一并拷贝</li>
     * <li>如果源数据为null，则该属性不拷贝</li>
     * </ul>
     *
     * @param src    源目标
     * @param target 对象目标
     */
    public static void copyBean(Object src, Object target) {
        if (src == null || target == null) {
            return;
        }
        Class<?> srcClass = src.getClass();
        copy(src, target, srcClass);
    }

    /**
     * 指定源类型拷贝
     *
     * @param src      源目标
     * @param target   对象目标
     * @param srcClass 源类型
     */
    private static void copy(Object src, Object target, Class<?> srcClass) {
        Field[] srcFields = srcClass.getDeclaredFields();
        Class<?> targetClass = target.getClass();
        if (CollectionUtil.isNotEmpty(srcFields)) {
            for (Field srcField : srcFields) {
                String srcFieldName = srcField.getName();
                try {
                    Object srcFieldValue = getFieldValue(srcClass, srcFieldName, src);
                    if (srcFieldValue == null) {
                        continue;
                    }
                    StringBuilder setterMethod = new StringBuilder(SET_METHOD_PREFIX)
                            .append(srcFieldName.substring(0, 1).toUpperCase())
                            .append(srcFieldName.substring(1));
                    Method targetMethod;
                    Class<?> srcFieldValueClass = getFieldGetter(srcClass, srcFieldName).getReturnType();
                    try {
                        targetMethod = targetClass.getMethod(setterMethod.toString(), srcFieldValueClass);
                    } catch (NoSuchMethodException e) {
                        setterMethod = new StringBuilder(SET_METHOD_PREFIX)
                                .append(srcFieldName);
                        try {
                            targetMethod = targetClass.getMethod(setterMethod.toString(), srcFieldValueClass);
                        } catch (NoSuchMethodException e1) {
                            if (!srcFieldName.startsWith("is")) {
                                continue;
                            }
                            setterMethod = new StringBuilder(SET_METHOD_PREFIX)
                                    .append(srcFieldName.substring(2, 3).toUpperCase())
                                    .append(srcFieldName.substring(3));
                            try {
                                targetMethod = targetClass.getMethod(setterMethod.toString(), srcFieldValueClass);
                            } catch (NoSuchMethodException e2) {
                                continue;
                            }
                        }
                    }
                    targetMethod.invoke(target, srcFieldValue);
                } catch (IllegalAccessException e) {
                    throw new RuntimeException(e);
                } catch (InvocationTargetException e) {
                    throw new RuntimeException(e);
                }
            }
        }
        if (srcClass.getSuperclass() == Object.class) {
            return;
        }
        copy(src, target, srcClass.getSuperclass());
    }

    /**
     * 实体拷贝
     * <p>
     * 根据传递的被拷贝对象的类型，创建出对象实例，并拷贝
     * </p>
     *
     * @param src    源目标
     * @param tClass 对象构造class
     * @param <T>    对象构造类型泛型
     * @return 被拷贝对象实例
     * @see #copyBean(Object, Object)
     */
    public static <T> T createAndCopy(Object src, Class<T> tClass) {
        if (tClass == null) {
            return null;
        }
        try {
            T target = tClass.newInstance();
            copyBean(src, target);
            return target;
        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 实体列表拷贝
     *
     * @param srcList 源目标列表
     * @param tClass  对象构造class
     * @param <T>     对象构造类型泛型
     * @return 被拷贝对象实例列表
     * @see #copyBean(Object, Object)
     * @see #createAndCopy(Object, Class)
     */
    @SuppressWarnings("unchecked")
    public static <T> List<T> createAndCopyList(List<?> srcList, Class<T> tClass) {
        if (tClass == null) {
            return null;
        }
        List<T> targetList = CollectionUtil.newList();
        if (CollectionUtil.isEmpty(srcList)) {
            return targetList;
        }
        for (Object src : srcList) {
            targetList.add(createAndCopy(src, tClass));
        }
        return targetList;
    }

}
